package yl.hs.bmipfull.utils;

import org.springframework.web.multipart.MultipartFile;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

/**
 * 作用:   <br/>
 * 创建时间: 2021-05-14 11:17 <br/>
 *
 * @author 张凯
 */
@SuppressWarnings("AlibabaClassNamingShouldBeCamel")
public class AESUtil {

    /**
     * AES加密初始化
     *
     * @param sKey       key
     * @param cipherMode 密码
     * @return {@link Cipher}
     */
    public static Cipher initAESCipher(String sKey, int cipherMode) {
        KeyGenerator generator = null;
        Cipher cipher = null;
        try {
            generator = KeyGenerator.getInstance("AES");
            generator.init(128, new SecureRandom(sKey.getBytes()));
            SecretKey secretKey = generator.generateKey();
            byte[] codeFormat = secretKey.getEncoded();
            SecretKeySpec keySpec = new SecretKeySpec(codeFormat, "AES");
            cipher = Cipher.getInstance("AES");
            cipher.init(cipherMode, keySpec);


        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException e) {
            e.printStackTrace();
        }
        return cipher;
    }

    /**
     * 文件格式化
     *
     * @param uploadFile  上传文件
     * @param localFile   本地文件
     * @param encryptFile 目标文件
     * @param sKey        密钥
     * @param type        加密类型
     * @return
     */
    public static File enOrDeFile(MultipartFile uploadFile, File localFile, File encryptFile, String sKey, int type) {
        InputStream inputStream = null;
        OutputStream outputStream = null;

        try {
            if (uploadFile != null) {
                inputStream = uploadFile.getInputStream();
            }
            if (localFile != null) inputStream = new FileInputStream(localFile);
            outputStream = new FileOutputStream(encryptFile);
            Cipher cipher = initAESCipher(sKey, type);

            CipherInputStream cipherInputStream = null;
            CipherOutputStream cipherOutputStream = null;
            if (Cipher.ENCRYPT_MODE == type) {
                // 创建加密流
                cipherInputStream = new CipherInputStream(inputStream, cipher);
            } else if (Cipher.DECRYPT_MODE == type) {
                // 创建解密流
                cipherOutputStream = new CipherOutputStream(outputStream, cipher);
            }

            byte[] cache = new byte[1024];

            int isread = 0;
            if (Cipher.ENCRYPT_MODE == type) {
                // 加密流写入文件
                while ((isread = cipherInputStream.read(cache, 0, cache.length)) != -1) {

                    outputStream.write(cache, 0, isread);
                }
            } else if (Cipher.DECRYPT_MODE == type) {
                // 解密流开始写入文件
                while ((isread = inputStream.read(cache, 0, cache.length)) != -1) {

                    cipherOutputStream.write(cache, 0, isread);
                }
            }

            if (cipherInputStream != null) cipherInputStream.close();
            if (cipherOutputStream != null) cipherOutputStream.close();

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (outputStream != null) {
                    outputStream.close();
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return encryptFile;
    }


    /**
     * 文件加密
     *
     * @param sourceFile  原文件
     * @param encryptFile 加密后文件
     * @param sKey        秘钥
     * @return {@link File}
     */
    public static File encryptFile(MultipartFile sourceFile, File encryptFile, String sKey) {
        File file = enOrDeFile(sourceFile, null, encryptFile, sKey, Cipher.ENCRYPT_MODE);
        return file;
    }

    /**
     * 文件解密
     *
     * @param sourceFile  http通讯文件
     * @param encryptFile 目标文件
     * @param sKey        密钥
     * @return {@link File}
     */
    public static File decryptFile(MultipartFile sourceFile, File encryptFile, String sKey) {
        File file = enOrDeFile(sourceFile, null, encryptFile, sKey, Cipher.DECRYPT_MODE);
        return file;
    }

    /**
     * 加密文件
     *
     * @param sourceFile  源文件
     * @param encryptFile 目标文件
     * @param sKey        密钥
     * @return {@link File}
     */
    public static File encryptFile(File sourceFile, File encryptFile, String sKey) {
        File file = enOrDeFile(null, sourceFile, encryptFile, sKey, Cipher.ENCRYPT_MODE);
        return file;
    }

    public static byte[] encryptData(byte[] data,String key) throws IOException {
        BufferedInputStream bis=null;
        ByteArrayOutputStream bos = null;
        try{
            bis = new BufferedInputStream(new ByteArrayInputStream(data));
            bos = new ByteArrayOutputStream();
            int b;
            while ((b=bis.read())!=-1){
                var ase = key.toCharArray();
                int c = -1;
                for (char ch:ase){
                    c = (c==-1?b:c)^ch;
                }
                bos.write(c);
            }
        }
        catch (Exception ee){
            throw ee;
        }
        finally {
            try{
                if(bis!=null){
                    bis.close();
                }
                if(bos!=null){
                    bos.close();
                }
            }catch (Exception ee){
                ee.printStackTrace();
            }
        }
        return bos.toByteArray();
    }
}
